package se.perp.c4.model;

import java.util.List;
import java.util.logging.Logger;
import static se.perp.c4.model.Actor.EActor.*;
import static se.perp.c4.model.Card.ECard.*;
import se.perp.c4.model.Card.ECard;
import se.perp.c4.model.Territory.ETerritory;

public class Battler {

    public static boolean orcsMayKill() {
        return !orcsHaveAttacked;
    }

    private Actor attacker,  defender;
    private final TerritoryCollection terrColl;
    private static boolean orcsHaveAttacked = false;
    private ECard attackerCard = null;
    private ECard defenderCard = null;

    public enum Result {
        NO_RESULT, ATTACKER_WIN, DEFENDER_WIN, ATTACKER_RETREAT, DEFENDER_RETREAT, BOTH_DIE, BOTH_RETREAT
    }

    public static void nextTurn() {
        orcsHaveAttacked = false;
    }

    public static void setOrcsHaveAttacked(boolean b) {
        orcsHaveAttacked = b;
    }

    public Battler(Actor attacker, Actor defender, final TerritoryCollection tc) {
        this.attacker = attacker;
        this.defender = defender;
        this.terrColl = tc;
    }

    public Result instantResolution() {

        Logger.getLogger(Battler.class.getName()).info("Checking instant resolution. attacker="+attacker.name + " ["+attacker.where+"]   defender="+defender.name + " ["+defender.where+"]");
        if (attacker.who == ORCS) {
            if (defender.who != GIMLI && defender.who != BOROMIR && defender.who != FRODO) {
                if (!orcsHaveAttacked) {
                    orcsHaveAttacked = true;
                    return Result.ATTACKER_WIN;
                }
            } else if (defender.who == GIMLI) {
                return Result.DEFENDER_WIN;
            } else if (defender.who == BOROMIR) {
                return Result.BOTH_DIE;
            } else if (defender.who == FRODO) {
                return Result.NO_RESULT;
            }
        }

        if (attacker.who == GIMLI && defender.who == ORCS) {
            return Result.ATTACKER_WIN;
        }

        if (attacker.who == MERRY && defender.who == WITCHKING) {
            return Result.ATTACKER_WIN;
        }
        if (attacker.who == WITCHKING && defender.who == MERRY) {
            return Result.DEFENDER_WIN;
        }

        if (attacker.who == LEGOLAS && defender.who == F_NAZGUL) {
            return Result.ATTACKER_WIN;
        }
        if (attacker.who == F_NAZGUL && defender.who == LEGOLAS) {
            return Result.DEFENDER_WIN;
        }

        if (attacker.who == BOROMIR && defender.who != WARG) {
            return Result.BOTH_DIE;
        }
        if (attacker.who != WARG && defender.who == BOROMIR) {
            return Result.BOTH_DIE;
        }


        return Result.NO_RESULT;
    }

    public void setAttackerCard(Card.ECard type) {
        attackerCard = type;
    }

    public void setDefenderCard(Card.ECard type) {
        defenderCard = type;
    }

    public Result resolve() {

        boolean noCards = attackerCard == null && defenderCard == null;
        boolean useCards = attackerCard != null && defenderCard != null;

        if (!noCards && !useCards) {
           Logger.getLogger(Battler.class.getName()).warning("Should only resolve battle with either zero or two cards. Bug?");
        }

        boolean attackerMayRetreatBackwards =
                canRetreatBackwards(attacker, defender.where);
        boolean attackerMayRetreatSideways =
                canRetreatSideways(attacker, defender.where);
        boolean defenderMayRetreatBackwards =
                canRetreatBackwards(defender, defender.where);
        boolean defenderMayRetreatSideways =
                canRetreatSideways(defender, defender.where);


        int attackerValue = attacker.attackValue;
        int defenderValue = defender.attackValue;

        // If we have cards, we should add their attack value.
        // Special case 1: Troll -> ignore dark attack value.
        // Special case 2: Light plays Elven cloak -> ignore dark attack value.
        //    (unless dark plays Eye of Sauron, but then it doesn't matter at all.
        boolean attackerIsTroll = attacker.who == CAVETROLL;
        boolean defenderIsTroll = defender.who == CAVETROLL;
        if (useCards) {

            boolean attackerElvenCloak = attackerCard == ELVEN_CLOAK;
            boolean defenderElvenCloak = defenderCard == ELVEN_CLOAK;

            if (!attackerIsTroll && !defenderElvenCloak) {
                attackerValue += Card.attackValue(attackerCard);
            }
            if (!defenderIsTroll && !attackerElvenCloak) {
                defenderValue += Card.attackValue(defenderCard);
            }
        }

        boolean attackerNoble = attackerCard == NOBLE_SACRIFICE;
        boolean defenderNoble = defenderCard == NOBLE_SACRIFICE;
        boolean attackerEye = attackerCard == EYE_OF_SAURON;
        boolean defenderEye = defenderCard == EYE_OF_SAURON;
        boolean attackerRetreat =
                !attackerIsTroll && 
                ((attackerCard == RETREAT_BACK && attackerMayRetreatBackwards) ||
                (attackerCard == RETREAT_SIDEWAYS && attackerMayRetreatSideways));
        boolean defenderRetreat =
                !defenderIsTroll &&
                ((defenderCard == RETREAT_BACK  && defenderMayRetreatBackwards) ||
                (defenderCard == RETREAT_SIDEWAYS && defenderMayRetreatSideways));


        if (attackerNoble &&
                (defenderIsTroll || (!defenderEye && !defenderRetreat))) {
            return Result.BOTH_DIE;
        }
        if (defenderNoble && (attackerIsTroll || (!attackerEye && !attackerRetreat))) {
            return Result.BOTH_DIE;
        }

        if (attackerRetreat && !defenderRetreat) {
            if (!defenderEye || defenderIsTroll) {
                return Result.ATTACKER_RETREAT;
            }
        }

        if (defenderRetreat && !attackerRetreat) {
            if (!attackerEye || attackerIsTroll) {
                return Result.DEFENDER_RETREAT;
            }
        }

        if (attackerRetreat && defenderRetreat ) {
            return Result.BOTH_RETREAT;
        }

        if (attackerValue < defenderValue) {
            return Result.DEFENDER_WIN;
        } else if (attackerValue == defenderValue) {
            return Result.BOTH_DIE;
        } else {
            return Result.ATTACKER_WIN;
        }

    }

    private boolean canRetreatBackwards(Actor actor, ETerritory from) {
        List<Territory.ETerritory> valid = terrColl.getValidBackwardsRetreats(actor, from);
        return valid.size() > 0;
    }

    private boolean canRetreatSideways(Actor actor, ETerritory from) {
        List<Territory.ETerritory> valid = terrColl.getValidSidewaysRetreats(actor, from);
        return valid.size() > 0;
    }
   
}
